﻿//*****************************************************************************
//
//! \file UC1701.c
//! \brief the UC1701 Driver.
//! \version V2.1.1.0
//! \date 1/24/2013
//! \author Nemon
//! \copy
//!
//! Copyright (c)  2013, Nemon
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//!     * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//!     * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//!     * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//*****************************************************************************
#include "vConsoleMenu.h"

//MENU_DEFINE_SELECTED_EVENT_FUNC(Cosnole_DefaultMenuOnSelected);

//*****************************************************************************
//
//! \brief Init the menu.
//!
//! \param stCosnoleMenuRoot *stCosnoleMenuRoot : root handle of the menu
//!
//! \param stCosnoleMenu *ptr_root : array of menu items
//!
//! \param s_menu_label_back_string[MENU_LABEL_LENGTH] : title of menu .
//!
//! \MENU_FUNC_EVENT_ON_SELECTED ptrFuncMenuOnSelected : handle event when a menu be Selected
//!
//! \param MENU_FUNC_EVENT_ON_SELECTED ptrFuncMenuOnCommand : handle event when a command menu be Selected
//!
//! \param MENU_FUNC_EVENT_ON_SELECTED ptrFuncMenuOnSubMenu : handle event when a parent menu be Selected
//!
//! This function initialize the menu.
//!
//! \return None.
//
//*****************************************************************************

void Cosnole_Menu_Init
(
	struct stCosnoleMenuRoot *stCosnoleMenuRoot
   ,struct stCosnoleMenu *ptr_root
   ,char s_menu_label_back_string[MENU_LABEL_LENGTH]
   ,MENU_FUNC_EVENT_ON_SELECTED ptrFuncMenuOnSelected
   ,MENU_FUNC_EVENT_ON_SELECTED ptrFuncMenuOnCommand
   ,MENU_FUNC_EVENT_ON_SELECTED ptrFuncMenuOnSubMenu
)
{
	unsigned int i;

	stCosnoleMenuRoot->menu_length=0;
	stCosnoleMenuRoot->root=ptr_root;

	//stCosnoleMenuRoot->root[MENU_ID_ROOT].menu_label="<<<back";
	for(i=0;i<MENU_LABEL_LENGTH;i++)
	{
		stCosnoleMenuRoot->root[MENU_ID_ROOT].menu_label[i]=s_menu_label_back_string[i] ;
	}
	stCosnoleMenuRoot->root[MENU_ID_ROOT].menu_parent_id=MENU_ID_ROOT;
	stCosnoleMenuRoot->root[MENU_ID_ROOT].menu_type_and_cmd=(MENU_COMMAND_NONE <<MENU_COMMAND_SHIFT) | (MENU_TYPE_COMMAND<<MENU_TYPE_SHIFT) | (MENU_CHECK_FALSE<<MENU_CHECK_FALSE) ;


	stCosnoleMenuRoot->menu_current_parent=MENU_ID_ROOT ;
	stCosnoleMenuRoot->funcMenuOnSelected=ptrFuncMenuOnSelected ;
	stCosnoleMenuRoot->funcMenuOnCommand=ptrFuncMenuOnCommand ;
	stCosnoleMenuRoot->funcMenuOnSubMenu=ptrFuncMenuOnSubMenu ;
}
//*****************************************************************************
//
//! \brief add a menu item to menu root.
//!
//! \param struct stCosnoleMenuRoot *stRoot: menu root
//!
//! \param unsigned int ui_menu_parent_id: parent menu id
//!
//! \param MENU_COMMAND_DATA_TYPE i_menu_cmd_id: command id,use for event handler
//!
//! \param char s_menu_label[MENU_LABEL_LENGTH]: label to show
//!
//! \param char c_menu_type:menu type, should be one of list --
//!                                    MENU_TYPE_COMMAND  3
//!                                    MENU_TYPE_PARENT   0
//!                                    MENU_TYPE_CHECK    1
//!                                    MENU_TYPE_OPTION   2
//!
//! \param char c_menu_checked: is menu be checked, should be one of list --
//!                                    MENU_CHECK_TRUE  1
//!                                    MENU_CHECK_FALSE 0
//!
//! \param char c_shortcut_key: a char,use for method "Cosnole_MenuOnSelected_by_ShortKey"
//!
//! This function make a menu item and ad it to menu root be given.
//!
//! \return unsigned int:id of menu item just be added.
//
//*****************************************************************************
unsigned int Cosnole_Add_A_Menu(
		struct stCosnoleMenuRoot *stRoot,
		unsigned int ui_menu_parent_id,
		MENU_COMMAND_DATA_TYPE i_menu_cmd_id,
		char s_menu_label[MENU_LABEL_LENGTH],
		char c_menu_type,
		char c_menu_checked,
		char c_shortcut_key
)
{
	unsigned int i;
	unsigned int uilength;

	uilength=stRoot->menu_length+1;
	//stCosnoleMenuRoot->root[uilength]->menu_parent_id = ui_menu_parent_id ;

	struct stCosnoleMenu *tmpMenu=&(stRoot->root[uilength]);
	tmpMenu->menu_parent_id = ui_menu_parent_id ;
	for(i=0;i<MENU_LABEL_LENGTH;i++)
	{
		tmpMenu->menu_label[i]=s_menu_label[i] ;
	}
	tmpMenu->menu_type_and_cmd = (i_menu_cmd_id <<MENU_COMMAND_SHIFT) | (c_menu_type<<MENU_TYPE_SHIFT) | (c_menu_checked<<MENU_CHECK_SHIFT) ;
	tmpMenu->shortcut_key=c_shortcut_key ;

	//tmpBuf[uilength]=&tmpMenu;
	stRoot->menu_length=uilength;

	return uilength;
}

//*****************************************************************************
//
//! \brief method,use when a Menu item should be Selected.
//!
//! \param struct stCosnoleMenuRoot *stRoot: menu root
//!
//! \param unsigned int uiMenuID: id of menu item just be selected
//!
//! use when a Menu item should be Selected.
//!
//! \return None
//
//*****************************************************************************

void Cosnole_MenuOnSelected (struct stCosnoleMenuRoot *stRoot,unsigned int uiMenuID)
{
	unsigned int i;
	struct stCosnoleMenu *tmpMenu=&(stRoot->root[uiMenuID]);
	if(uiMenuID==MENU_ID_ROOT)
	{
		stRoot->menu_current_parent=tmpMenu->menu_parent_id;
		if(stRoot->funcMenuOnSubMenu)
		{
			stRoot->funcMenuOnSubMenu(stRoot,tmpMenu->menu_parent_id);
		}
	}
	else
	{
		char cType=MENU_GET_TYPE(tmpMenu->menu_type_and_cmd);
		switch(cType)
		{
		case MENU_TYPE_COMMAND:
			if( stRoot->funcMenuOnCommand && MENU_GET_CMD_ID(tmpMenu->menu_type_and_cmd)!=MENU_COMMAND_NONE )
			{
				stRoot->funcMenuOnCommand(stRoot,MENU_GET_CMD_ID(tmpMenu->menu_type_and_cmd));
			}
			break;
		case MENU_TYPE_PARENT:
			stRoot->menu_current_parent=uiMenuID;

			//change focus on first item
			for(i=1;i<=stRoot->menu_length;i++)
			{
				if(stRoot->root[i].menu_parent_id==stRoot->menu_current_parent)
				{
					stRoot->menu_current_focus=i;
					break;
				}
			}


			if(stRoot->funcMenuOnSubMenu)
			{
				stRoot->funcMenuOnSubMenu(stRoot,uiMenuID);
			}
			break;
		case MENU_TYPE_CHECK:
			if(MENU_GET_CHECKED(tmpMenu->menu_type_and_cmd)==MENU_CHECK_FALSE)
			{
				tmpMenu->menu_type_and_cmd=tmpMenu->menu_type_and_cmd | MENU_CHECK_MASK_1;
			}
			else
			{
				tmpMenu->menu_type_and_cmd=tmpMenu->menu_type_and_cmd & MENU_CHECK_MASK_0;
			}

			if(stRoot->funcMenuOnSelected)
			{
				stRoot->funcMenuOnSelected(stRoot,uiMenuID);
			}
			break;
		case MENU_TYPE_OPTION:
			for(i=1;i<stRoot->menu_length;i++)
			{
				if((stRoot->root[i].menu_parent_id)==(tmpMenu->menu_parent_id) && MENU_GET_TYPE(stRoot->root[i].menu_type_and_cmd)==MENU_TYPE_OPTION)
				{
					stRoot->root[i].menu_type_and_cmd=tmpMenu->menu_type_and_cmd & MENU_CHECK_MASK_0;
				}
			}
			tmpMenu->menu_type_and_cmd=tmpMenu->menu_type_and_cmd | MENU_CHECK_MASK_1;

			if(stRoot->funcMenuOnSelected)
			{
				stRoot->funcMenuOnSelected(stRoot,uiMenuID);
			}
			break;
		}
		/*
		if(MENU_GET_CMD_ID(tmpMenu->menu_type_and_cmd)!=MENU_COMMAND_NONE)
		{
			stRoot->funcMenuOnCommand(MENU_GET_CMD_ID(tmpMenu->menu_type_and_cmd));
		}
		*/
	}
}

//*****************************************************************************
//
//! \brief method, get menu items array which should be show .
//!
//! \param struct stCosnoleMenuRoot *stRoot: menu root
//!
//! \param struct stCosnoleMenu **menuBuff: array for store id of menu item should be show
//!
//! \param unsigned int uiViewSize: limit size of menuBuff
//!
//! \param unsigned int uiPositionStart: position of first menu item should accept collect into  array
//!
//! get menu items array which should be show .
//!
//! \return None
//
//*****************************************************************************

unsigned int Cosnole_GetCurrentViewMenus(
		struct stCosnoleMenuRoot *stRoot,
		struct stCosnoleMenu **menuBuff,
		unsigned int uiViewSize,
		unsigned int uiPositionStart
)
{
	unsigned int i,uiCount=0;
	for(i=1;i<=stRoot->menu_length && uiCount<=uiViewSize;i++)
	{
		if(stRoot->root[i].menu_parent_id==stRoot->menu_current_parent)
		{
			if(uiCount>=uiPositionStart)
			{
				menuBuff[uiCount]=&(stRoot->root[i]);
			}
			uiCount++;
		}
	}
	return uiCount;
}

//*****************************************************************************
//
//! \brief method, to select a menu item by it's shortkey char.
//!
//! \param struct stCosnoleMenuRoot *stRoot: menu root
//!
//! \param char c_short_key: shortkey char
//!
//! to select a menu item by it's shortkey char.
//!
//! \return None
//
//*****************************************************************************

void Cosnole_MenuOnSelected_by_ShortKey (struct stCosnoleMenuRoot *stRoot,char c_short_key)
{
	unsigned int i;
	for(i=1;i<=stRoot->menu_length;i++)
	{
		if(stRoot->root[i].menu_parent_id==stRoot->menu_current_parent && stRoot->root[i].shortcut_key==c_short_key)
		{
			Cosnole_MenuOnSelected (stRoot,i);
			return;
		}
	}
}

//*****************************************************************************
//
//! \brief method, to goto parent menu of current menu item .
//!
//! \param struct stCosnoleMenuRoot *stRoot: menu root
//!
//! to goto parent menu of current menu item .
//!
//! \return None
//
//*****************************************************************************

void Cosnole_MenuBackUp (struct stCosnoleMenuRoot *stRoot)
{
	int i;
	if(stRoot->menu_current_parent!=MENU_ID_ROOT)
	{
		//change focus on this item
		stRoot->menu_current_focus=stRoot->menu_current_parent;

		//change parent node
		stRoot->menu_current_parent=stRoot->root[stRoot->menu_current_parent].menu_parent_id;


		if(stRoot->funcMenuOnSubMenu)
		{
			stRoot->funcMenuOnSubMenu(stRoot,stRoot->menu_current_parent);
		}
	}
}

//*****************************************************************************
//
//! \brief method, scoll focus up .
//!
//! \param struct stCosnoleMenuRoot *stRoot: menu root
//!
//! scoll focus up .
//!
//! \return None
//
//*****************************************************************************

void Cosnole_MenuScorllUp (struct stCosnoleMenuRoot *stRoot)
{
	unsigned int i;
	for(i=stRoot->menu_current_focus-1;i>MENU_ID_ROOT;i--)
	{
		if(stRoot->root[i].menu_parent_id==stRoot->menu_current_parent)
		{
			stRoot->menu_current_focus=i;
			return;
		}
	}
	//if(i<=0);
}

//*****************************************************************************
//
//! \brief method, scoll focus down .
//!
//! \param struct stCosnoleMenuRoot *stRoot: menu root
//!
//! scoll focus down .
//!
//! \return None
//
//*****************************************************************************

void Cosnole_MenuScorllDown (struct stCosnoleMenuRoot *stRoot)
{
	unsigned int i;
	for(i=stRoot->menu_current_focus+1;i<stRoot->menu_length;i++)
	{
		if(stRoot->root[i].menu_parent_id==stRoot->menu_current_parent)
		{
			stRoot->menu_current_focus=i;
			return;
		}
	}
	//if(i>=stRoot->menu_current_focus);
}

//*****************************************************************************
//
//! \brief method, select menu item which is focused .
//!
//! \param struct stCosnoleMenuRoot *stRoot: menu root
//!
//! select menu item which is focused .
//!
//! \return None
//
//*****************************************************************************

void Cosnole_MenuOnSelected_by_Focus (struct stCosnoleMenuRoot *stRoot)
{
	Cosnole_MenuOnSelected(stRoot,stRoot->menu_current_focus);
}

//*****************************************************************************
//
//! \brief method, get menu items array arrounding the focused menu item which should be show, the Focused menu item may be 1st .
//!
//! \param struct stCosnoleMenuRoot *stRoot: menu root
//!
//! \param struct stCosnoleMenu **menuBuff: array for store id of menu item should be show
//!
//! \param unsigned int uiViewSize: limit size of menuBuff
//!
//! get menu items array arrounding the focused menu item which should be show, the Focused menu item may be 1st .
//!
//! \return None
//
//*****************************************************************************

unsigned int Cosnole_GetCurrentViewFocusedMenus(struct stCosnoleMenuRoot *stRoot,struct stCosnoleMenu **menuBuff,unsigned int uiViewSize)
{
	int i,j,uiCount=0;
	for(i=stRoot->menu_current_focus;i<stRoot->menu_length && uiCount<=uiViewSize;i++)
	{
		if(
				i!=MENU_ID_ROOT
				&&
				stRoot->root[i].menu_parent_id==stRoot->menu_current_parent
		)
		{
			menuBuff[uiCount]=&(stRoot->root[i]);
			uiCount++;
		}
	}
	if(uiCount<uiViewSize)
	{
		for(i=stRoot->menu_current_focus-1;i>0 && uiCount<=uiViewSize;i--)
		{
			if(stRoot->root[i].menu_parent_id==stRoot->menu_current_parent)
			{
				for(j=uiCount-1;j>=MENU_ID_ROOT;j--)
				{
					menuBuff[j+1]=menuBuff[j];
				}
				menuBuff[0]=&(stRoot->root[i]);
				uiCount++;
			}
		}
	}
	return uiCount;
}
